package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name   string `json:"name"` // 指定json序列化/反序列化时使用小写name
	Age    int64
	Weight float64 `json:"-"` // 指定json序列化/反序列化时忽略此字段
}

type User struct {
	Name  string   `json:"name"`
	Email string   `json:"email"`
	Hobby []string `json:"hobby"`
	// 想要变成嵌套的json串，需要改为具名嵌套或定义字段tag
	Profile `json:"profile,omitempty"`
}

type UserProfile struct {
	Name  string   `json:"name"`
	Email string   `json:"email"`
	Hobby []string `json:"hobby"`
	// 想要变成嵌套的json串，需要改为具名嵌套或定义字段tag
	*Profile `json:"profile,omitempty"`
}

type Profile struct {
	WebSite string `json:"website"`
	Slogan  string `json:"slogan"`
}

func nestedStructDemo(_type string) {
	if _type != "empty" {
		u := User{
			Name:  "七米",
			Hobby: []string{"足球", "双色球"},
			Profile: Profile{
				WebSite: "123",
				Slogan:  "lws",
			},
		}
		b, _ := json.Marshal(u)
		fmt.Printf("str: %s\n", b)
	} else {
		u := UserProfile{
			Name:  "七米",
			Hobby: []string{"足球", "双色球"},
		}
		b, _ := json.Marshal(u)
		fmt.Printf("str: %s\n", b)
	}
}

// 在tag中添加omitempty忽略空值
// 注意这里 hobby,omitempty 合起来是json tag值，中间用英文逗号分隔
type UserAllowEmpty struct {
	Name  string   `json:"name"`
	Email string   `json:"email,omitempty"`
	Hobby []string `json:"hobby,omitempty"`
}

type UserInfo struct {
	Id   int    `json:"id"`
	Name string `json:"name"`
}

func anonymousStructDemo() {
	var u1 = UserInfo{
		Id:   1,
		Name: "娜扎",
	}
	// 使用匿名结构体添加额外字段Token
	b, err := json.Marshal(struct {
		*UserInfo
		Token string `json:"token"`
	}{
		&u1,
		"91je3a4s72d1da96h",
	})
	if err != nil {
		fmt.Println("json marshal failed, err: ", err)
		return
	}
	fmt.Printf("str: %s\n", b)
}

func main() {
	var p1 = Person{
		Name:   "小王子",
		Age:    18,
		Weight: 71.5,
	}
	// 1. struct -> json string  ===> 编码(序列化：将结构体转化为string)
	b, err := json.Marshal(p1)
	if err != nil {
		fmt.Println("json marshal failed, err: ", err)
	}
	fmt.Printf("str: %s\n", b) // str: {"Name":"小王子","Age":18,"Weight":71.5}

	// 2. json string -> struct  ===> 解码(反序列化：将string还原为结构体)
	var p2 Person
	if err = json.Unmarshal(b, &p2); err != nil {
		fmt.Printf("json.Unmarshal failed, err:%v\n", err)
		return
	}
	fmt.Printf("p2: %#v\n", p2) // p2: main.Person{Name:"小王子", Age:18, Weight:71.5}

	// 3. 忽略空值字段
	// 3.1
	var u1 = User{
		Name: "娜扎",
	}
	c, err := json.Marshal(u1)
	if err != nil {
		fmt.Printf("json.Marshal failed, err:%v\n", err)
		return
	}
	fmt.Printf("str: %s\n", c) // str: {"name":"娜扎","email":"","hobby":null}

	// 3.2
	var u2 = UserAllowEmpty{
		Name: "灰太狼",
	}
	d, _ := json.Marshal(u2)
	fmt.Printf("str: %s\n", d) // str: {"name":"灰太狼"}

	// 4. 忽略嵌套结构体空值字段
	nestedStructDemo("other") // str: {"name":"七米","email":"","hobby":["足球","双色球"],"profile":{"website":"123","slogan":"lws"}'
	nestedStructDemo("empty") // str: {"name":"七米","email":"","hobby":["足球","双色球"]}

	// 5. 使用匿名结构体添加字段
	anonymousStructDemo() // str: {"id":1,"name":"娜扎","token":"91je3a4s72d1da96h"}

	// 6. json.MarshalIndent() == python中的pprint()
	type Movie struct {
		Title  string
		Year   int  `json:"released"`
		Color  bool `json:"color,omitempty"`
		Actors []string
	}
	var movies = []Movie{
		{Title: "Casablanca", Year: 1942, Color: false, Actors: []string{"Humphrey Bogart", "Ingrid Bergman"}},
		{Title: "Cool Hand Luke", Year: 1967, Color: true, Actors: []string{"Paul Newman"}},
		{Title: "Bullitt", Year: 1968, Color: true, Actors: []string{"Steve McQueen", "Jacqueline Bisset"}},
	}
	movieRes, _ := json.MarshalIndent(movies, "", "   ")
	fmt.Printf("movieRes:%s\n", movieRes)
}
